package org.jheuristics.ga.multiObjective;

import java.util.ArrayList;
import java.util.List;

import org.jheuristics.ga.GAConfig;
import org.jheuristics.ga.GAStatus;
import org.jheuristics.ga.transformations.FitnessToDoubleTransformation;

/**
 * TODO
 *
 * @author Marcell Manfrin, marcell@ourgrid.org, Oct 27, 2005
 * @author Thiago Emmanuel Pereira da Cunha Silva, thiagoepdc@ourgrid.org, Oct 27, 2005
 */
public class EuclidianDistanceAlgorithm extends AbstractDistanceAlgorithm {

	/**
	 * TODO
	 *
	 * @param transformations
	 */
	public EuclidianDistanceAlgorithm(FitnessToDoubleTransformation[] transformations) {
		super(transformations);
	}

	/**
	 * TODO
	 *
	 * @param values
	 * @param status
	 * @param config
	 * @return
	 * @see org.jheuristics.ga.multiObjective.AbstractDistanceAlgorithm#getDensities(double[][], org.jheuristics.ga.GAStatus, org.jheuristics.ga.GAConfig)
	 */
	protected List[] getDistances(double[][] values, GAStatus status, GAConfig config) {
		double[] min = new double[values[0].length];
		double[] max = new double[values[0].length];
		for (int j = 0; j < values[0].length; j++) {
			min[j] = values[0][j];
			max[j] = values[0][j];
		}
		for (int i = 1; i < values.length; i++) {
			for (int j = 0; j < values[i].length; j++) {
				if (min[j] > values[i][j]) {
					min[j] = values[i][j];
				}
				if (max[j] < values[i][j]) {
					max[j] = values[i][j];
				}
			}
		}

		List[] distances = new List[values.length];
		for ( int i = 0; i < distances.length; i++ ) {
			distances[i] = new ArrayList(values.length-1);
		}

		for (int i = 0; i < values.length; i++) {
			for (int j = i + 1; j < values.length; j++) {
				Double distance = new Double(getDistance(values, min, max, i, j));
				distances[i].add(distance);
				distances[j].add(distance);
			}
		}
		return distances;
	}

	/**
	 * TODO
	 *
	 * @param values
	 * @param min
	 * @param max
	 * @param index1
	 * @param index2
	 * @return
	 */
	private double getDistance(double[][] values, double[] min, double[] max, int index1, int index2) {
		double result = 0.0;
		for (int i = 0; i < min.length; i++) {
			double delta = max[i] - min[i];
			double tmp = (values[index1][i] - values[index2][i]) / (0.0 == delta ? 1 : delta);
			result += (tmp * tmp);
		}
		return Math.sqrt(result);
	}

}